package cn.matezk.lianlian.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.matezk.lianlian.beans.Constant;
import cn.matezk.lianlian.dao.*;
import cn.matezk.lianlian.framework.RedisMutexLock;
import cn.matezk.lianlian.model.Device;
import cn.matezk.lianlian.model.NotifyRecord;
import cn.matezk.lianlian.model.NotifyTemplate;
import cn.matezk.lianlian.model.SecretKey;
import cn.matezk.lianlian.service.INotifyService;
import cn.matezk.lianlian.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class NotifyService implements INotifyService {
    @Autowired
    private NotifyTemplateDao notifyTemplateDao;
    @Autowired
    private SecretKeyDao secretKeyDao;
    @Autowired
    private NotifyRecordDao notifyRecordDao;
    @Autowired
    private DeviceDao deviceDao;
    @Autowired
    private UserDao userDao;
    @Autowired
    private RedisMutexLock mutexLock;

    @Override
    public NotifyTemplate matchTemplate(String appKey, String method, String eventKey) {
        if (ObjectUtil.isNotEmpty(appKey)) {
            NotifyTemplate template = notifyTemplateDao.match(appKey, eventKey, method);
            if (ObjectUtil.isNotNull(template)) return template;
        }
        return notifyTemplateDao.match("", eventKey, method);
    }

    @Override
    public List<String> wechatNotifyUser(String deviceId) {
        Device device = deviceDao.selectByPrimaryKey(deviceId);
        return userDao.selectWechatNotifyUser(device.getFamilyId(), deviceId);
    }

    @Override
    public void smsReport(JSONObject report) throws InterruptedException {
        String lockKey = NotifyRecord.createLockKey(report.getStr("biz_id"));
        if (mutexLock.tryLock(lockKey, 3)) {
            try {
                NotifyRecord record = notifyRecordDao.selectByBizId(report.getStr("biz_id"));
                if (ObjectUtil.isNull(record) || !NotifyRecord.STATUS_CONFIRM.equals(record.getStatus()))
                    return;
                record.setStatus(Boolean.TRUE.equals(report.getBool("success")) ? NotifyRecord.STATUS_SUCCESS : NotifyRecord.STATUS_FAILED);
                record.setErrorCode(StringUtils.sub(report.getStr("err_code"), 30));
                record.setErrorMsg(StringUtils.sub(report.getStr("err_msg"), 30));
                int count = notifyRecordDao.updateByBizId(record);
                if (count > 0 && Boolean.FALSE.equals(report.getBool("success"))) {
                    // 是否绑定APPKEY
                    SecretKey secretKey = secretKeyDao.deviceMatch(record.getProductId(), record.getDeviceName());
                    // 是否绑定了用户
                    Long userId = ObjectUtil.isNull(secretKey) ? null : secretKey.getBindUser();
                    String amountLockKey = Device.createLockKey(record.getDeviceId());
                    if (ObjectUtil.isNotNull(userId)) {
                        amountLockKey = String.format("lock.user.%d", userId);
                    }
                    if (mutexLock.tryLock(amountLockKey, 3)) {
                        try {
                            if (ObjectUtil.isNotNull(userId)) {
                                // 退还到账户余额
                                Integer amount = userDao.userAmount(userId);
                                userDao.updateAmount(userId, amount + Constant.SMS_UNIT_PRICE);
                            } else {
                                // 退还到设备余额
                                Device device = deviceDao.selectByPrimaryKey(record.getDeviceId());
                                deviceDao.updateAmount(device.getDeviceId(), device.getAmount() + Constant.SMS_UNIT_PRICE);
                            }
                        } finally {
                            mutexLock.unlock(amountLockKey);
                        }
                    }
                }
                if (NotifyRecord.STATUS_SUCCESS.equals(record.getStatus())) {
                    // 语音通知接听后不再重复推送
                    notifyRecordDao.cancelRepeatNotify(record.getEventId(), record.getToUser());
                }
            } finally {
                mutexLock.unlock(lockKey);
            }
        }
    }

    @Override
    public void ttsReport(JSONObject report) throws InterruptedException {
        String notifyLockKey = NotifyRecord.createLockKey(report.getStr("call_id"));
        if (mutexLock.tryLock(notifyLockKey, 3));
        try {
            String startTime = report.getStr("b_start_time");
            NotifyRecord record = notifyRecordDao.selectByBizId(report.getStr("call_id"));
            if (ObjectUtil.isNull(record))  return;
            record.setStatus(ObjectUtil.isEmpty(startTime) ? NotifyRecord.STATUS_FAILED : NotifyRecord.STATUS_SUCCESS);
            record.setErrorCode(report.getStr("status_code"));
            int count = notifyRecordDao.updateByBizId(record);
            if (count > 0 && NotifyRecord.STATUS_FAILED.equals(record.getStatus())) {
                // 是否绑定APPKEY
                SecretKey secretKey = secretKeyDao.deviceMatch(record.getProductId(), record.getDeviceName());
                // 是否绑定了用户
                Long userId = ObjectUtil.isNull(secretKey) ? null : secretKey.getBindUser();
                String amountLockKey = Device.createLockKey(record.getDeviceId());
                if (ObjectUtil.isNotNull(userId)) {
                    amountLockKey = String.format("lock.user.%d", userId);
                }
                if (mutexLock.tryLock(amountLockKey, 3)) {
                    try {
                        if (ObjectUtil.isNotNull(userId)) {
                            // 退还到账户余额
                            Integer amount = userDao.userAmount(userId);
                            userDao.updateAmount(userId, amount + Constant.TTS_UNIT_PRICE);
                        } else {
                            // 退还到设备余额
                            Device device = deviceDao.selectByPrimaryKey(record.getDeviceId());
                            deviceDao.updateAmount(device.getDeviceId(), device.getAmount() + Constant.TTS_UNIT_PRICE);
                        }
                    } finally {
                        mutexLock.unlock(amountLockKey);
                    }
                }
            }
        } finally {
            mutexLock.unlock(notifyLockKey);
        }
    }
}
